﻿#region File Description

//-----------------------------------------------------------------------------
// DataAccessObject.cs
//
// Author: ITU Team3 (2012)
//-----------------------------------------------------------------------------

#endregion File Description

#region Using Statements

using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Diagnostics.Contracts;
using System.Linq;
using rentit03_server.Business;

#endregion Using Statements

namespace rentit03_server.Database
{
    public class DataAccessObject : IDatabase
    {
        //User methods
        [Pure]
        public User AuthenticateUser(string email, string password)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var user = context.UserSet.FirstOrDefault(u => u.Email == email);
                return user != null && user.Password == password ? ReadUser(user.Id) : null;
            }
        }

        [Pure]
        public bool UsernameExists(string email)
        {
            using (var context = new RentIt03Entities())
            {
                return context.UserSet.Any(u => u.Email == email);
            }
        }

        public int CreateUser(User user)
        {
            using (var context = new RentIt03Entities())
            {
                if (user.Email != null && !UsernameExists(user.Email) && user.Password != null)
                {
                    user.Id = default(int);
                    user.Credits = 0;
                    user.Updated = DateTime.Now;
                    context.UserSet.AddObject(user);
                    context.SaveChanges();

                    var role = ReadRole("Authorized User");
                    AddRoleToUser(role.Id, user.Id);

                    return user.Id;
                }
                return -1;
            }
        }

        [Pure]
        public User ReadUser(int uId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var user = context.UserSet.Include("Roles").FirstOrDefault(u => u.Id == uId);

                if (user != null)
                {
                    user.Password = "[REMOVED]";
                    return user;
                }
                return new User();
            }
        }

        public bool EditUser(User user, int uId)
        {
            using (var context = new RentIt03Entities())
            {
                if (user == null)
                    return true;

                var editUser = context.UserSet.First(u => u.Id == uId);

                editUser.Email = user.Email;
                editUser.Name = user.Name;
                editUser.PhoneNumber = user.PhoneNumber;
                editUser.Address = user.Address;

                return context.SaveChanges() > 0;
            }
        }

        public bool DeleteUser(int uId)
        {
            using (var context = new RentIt03Entities())
            {
                var user = context.UserSet.FirstOrDefault(u => u.Id == uId);

                if (user != null)
                {
                    user.Roles.Clear();

                    for (var i = user.Comments.Count; i > 0; i--)
                        context.CommentSet.DeleteObject(user.Comments.First());

                    for (var i = user.Ratings.Count; i > 0; i--)
                        context.RatingSet.DeleteObject(user.Ratings.First());

                    for (var j = user.Purchases.Count; j > 0; j--)
                        context.PurchaseSet.DeleteObject(user.Purchases.First());

                    context.UserSet.DeleteObject(user);
                }

                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<User> OverviewUser(UserSearchParameter condition)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;

                var q = context.UserSet.OfType<User>();

                if (!string.IsNullOrWhiteSpace(condition.Name))
                    q = (ObjectQuery<User>)q.Where(u => u.Name.Contains(condition.Name));

                if (!string.IsNullOrWhiteSpace(condition.Email))
                    q = (ObjectQuery<User>)q.Where(u => u.Email.Contains(condition.Email));

                var count = condition.Count != null && condition.Count > 0 ? condition.Count : 20;
                var page = condition.Page != null && condition.Page > 0 ? condition.Page : 0;

                return condition.Count < 0
                           ? new List<User>(q.Count())
                           : q.OrderBy(u => u.Name).Skip((int)(page * count)).Take((int)count).ToList();
            }
        }

        public int OverviewUserCount(UserSearchParameter parem)
        {
            parem.Count = -1;
            return OverviewUser(parem).Capacity;
        }

        public bool AddRoleToUser(int rId, int uId)
        {
            using (var context = new RentIt03Entities())
            {
                var role = context.RoleSet.FirstOrDefault(r => r.Id == rId);
                var user = context.UserSet.FirstOrDefault(u => u.Id == uId);

                if (user != null)
                {
                    context.RoleSet.Attach(role);
                    user.Roles.Add(role);
                }

                return context.SaveChanges() > 0;
            }
        }

        public bool ChangePassword(int uId, string newPassword)
        {
            using (var context = new RentIt03Entities())
            {
                var user = context.UserSet.FirstOrDefault(u => u.Id == uId);
                if (user != null) user.Password = newPassword;
                return context.SaveChanges() > 0;
            }
        }

        public bool EditCredits(int uId, int amount)
        {
            using (var context = new RentIt03Entities())
            {
                var user = context.UserSet.FirstOrDefault(u => u.Id == uId);

                // Check for negative credits
                if (user.Credits + amount < 0)
                    throw new UserHandlerException(ReturnStatus.UserCreditNegativeAmount, "You can't have a negative amount of credits. Your current credit number is " + user.Credits + ".");

                user.Credits += amount;
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public int ReadCredits(int uId)
        {
            using (var context = new RentIt03Entities())
            {
                return (int)context.UserSet.FirstOrDefault(u => u.Id == uId).Credits;
            }
        }

        public int CreatePermission(RentitPermission permission)
        {
            using (var context = new RentIt03Entities())
            {
                var perm = new Permission { Id = permission.Id, Name = permission.Name };
                context.PermissionSet.AddObject(perm);
                return context.SaveChanges() > 0 ? perm.Id : -1;
            }
        }

        [Pure]
        public Permission ReadPermission(int pId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.PermissionSet.FirstOrDefault(p => p.Id == pId);
            }
        }

        [Pure]
        public Permission ReadPermission(string name)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.PermissionSet.FirstOrDefault(p => p.Name.Equals(name));
            }
        }

        public bool EditPermission(Permission permission, int pId)
        {
            using (var context = new RentIt03Entities())
            {
                var oldPermission = context.PermissionSet.FirstOrDefault(p => p.Id == pId);
                if (oldPermission != null) oldPermission.Name = permission.Name;
                return context.SaveChanges() > 0;
            }
        }

        public bool DeletePermission(int pId)
        {
            using (var context = new RentIt03Entities())
            {
                var permission = context.PermissionSet.FirstOrDefault(p => p.Id == pId);
                context.PermissionSet.DeleteObject(permission);
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Permission> OverviewPermission()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.PermissionSet.ToList();
            }
        }

        public bool AddPermissionToRole(int rId, int pId)
        {
            using (var context = new RentIt03Entities())
            {
                var role = context.RoleSet.FirstOrDefault(r => r.Id == rId);
                var permission = context.PermissionSet.FirstOrDefault(p => p.Id == pId);
                if (role != null && permission != null)
                {
                    context.PermissionSet.Attach(permission);
                    role.Permissions.Add(permission);
                }

                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Version> OverviewVersions(int mId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;

                var versions = context.VersionSet.Include("Medium").Where(v => v.MediaId == mId);
                return versions.ToList();
            }
        }

        [Pure]
        public Version ReadVersion(int vId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;

                return context.VersionSet.Include("Medium").FirstOrDefault(v => v.Id == vId);
            }
        }

        public int CreateRole(RentitRole role)
        {
            using (var context = new RentIt03Entities())
            {
                var r = new Role { Name = role.Name };
                context.RoleSet.AddObject(r);
                return context.SaveChanges() > 0 ? r.Id : -1;
            }
        }

        [Pure]
        public Role ReadRole(string name)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.RoleSet.Include("Permissions").FirstOrDefault(r => r.Name == name);
            }
        }

        [Pure]
        public RentitRole ReadRole(int rId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var role = context.RoleSet.Include("Permissions").FirstOrDefault(r => r.Id == rId);
                var permissionList = new List<string>();
                permissionList.AddRange(role.Permissions.Select(permission => permission.Name));

                return new RentitRole { Id = role.Id, Name = role.Name, Permissions = permissionList };
            }
        }

        public bool EditRole(Role role, int rId)
        {
            using (var context = new RentIt03Entities())
            {
                var newRole = context.RoleSet.FirstOrDefault(r => r.Id == rId);
                if (newRole != null) newRole.Name = role.Name;
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Role> OverviewRole()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.RoleSet.ToList();
            }
        }

        public bool Purchase(int uId, int vId, int cost)
        {
            using (var context = new RentIt03Entities())
            {
                var version = ReadVersion(vId);

                var purchase = new Purchase
                                   {
                                       StartTime = DateTime.Now,
                                       VersionId = vId,
                                       UserId = uId
                                   };

                if (version.RentDays != null && version.RentDays != 0)
                    purchase.EndTime = DateTime.Now.Add(new TimeSpan((int)version.RentDays, 0, 0, 0));

                context.PurchaseSet.AddObject(purchase);

                var user = context.UserSet.FirstOrDefault(u => u.Id == uId);
                if (user != null) user.Credits -= cost;

                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Purchase> OverviewPurchases(int uId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.PurchaseSet.Where(p => p.UserId == uId).ToList();
            }
        }

        //Media methods

        public int CreateMedia(Media media)
        {
            using (var context = new RentIt03Entities())
            {
                media.Id = default(int);
                media.Updated = DateTime.Now;
                media.Created = DateTime.Now;
                context.MediaSet.AddObject(media);
                context.SaveChanges();
                return media.Id;
            }
        }

        [Pure]
        public Media ReadMedia(int mId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.MediaSet.Include("Languages").Include("Images").Include("Genres").Include("Versions").Include("Comments").Include("Comments.User").FirstOrDefault(m => m.Id == mId);
            }
        }

        public Media ReadMedia(string mTitle, int mYear)
        {
            using (var context = new RentIt03Entities())
            {
                return context.MediaSet.FirstOrDefault(m => m.Title == mTitle && m.Year == mYear);
            }
        }

        [Pure]
        public Media ReadMediaFromVersionId(int vId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;

                //Using ReadMedia
                var version = context.VersionSet.FirstOrDefault(v => v.Id == vId);
                if (version != null)
                    return ReadMedia(version.MediaId);

                //OLD version - left there as backup!
                var mId = (from v in context.VersionSet.Include("Medium") where v.Id == vId select v.MediaId).FirstOrDefault();
                return (from m in context.MediaSet where m.Id == mId select m).FirstOrDefault();
            }
        }

        public bool EditMedia(Media media, int mId)
        {
            using (var context = new RentIt03Entities())
            {
                var editMedia = context.MediaSet.First(m => m.Id == mId);

                editMedia.Title = media.Title;
                editMedia.Year = media.Year;
                editMedia.CoverUrl = media.CoverUrl;
                editMedia.Description = media.Description;
                editMedia.Votes = media.Votes;
                editMedia.Rating = media.Rating;
                editMedia.Updated = media.Updated;
                editMedia.Released = media.Released;

                //Edit languages
                editMedia.Languages.Clear();
                for (var i = media.Languages.Count; i > 0; i--)
                {
                    var language = media.Languages.First();

                    var lang = context.LanguageSet.FirstOrDefault(l => l.Name == language.Name) ??
                                Language.CreateLanguage(default(int), language.Name);

                    editMedia.Languages.Add(lang);
                    media.Languages.Remove(language);
                }

                for (var i = media.Images.Count; i > 0; i--)
                {
                    var image = media.Images.First();
                    if (!editMedia.Images.Contains(image))
                    {
                        var imag = Image.CreateImage(default(int), image.Url, mId);
                        editMedia.Images.Add(imag);
                    }
                    else
                    {
                        editMedia.Images.Remove(image);
                        context.ImageSet.DeleteObject(image);
                    }
                    media.Images.Remove(image);
                }

                //Edit genres
                editMedia.Genres.Clear();
                for (var i = media.Genres.Count; i > 0; i--)
                {
                    var genre = media.Genres.First();

                    var gen = context.GenreSet.FirstOrDefault(g => g.Name == genre.Name) ??
                              Genre.CreateGenre(default(int), genre.Name, genre.MediaType);

                    editMedia.Genres.Add(gen);
                    media.Genres.Remove(genre);
                }

                //Edit versions
                /*
                editMedia.Versions.Clear();
                for (var i = media.Versions.Count; i > 0; i--)
                {
                    var version = media.Versions.First();

                    if (!editMedia.Versions.Contains(version))
                    {
                        var ver = Version.CreateVersion(default(int), version.Resolution, version.Format, version.Price, version.MediaId);
                        editMedia.Versions.Add(ver);
                    }
                    else
                    {
                        editMedia.Versions.Remove(version);
                        context.VersionSet.DeleteObject(version);
                    }
                    media.Versions.Remove(version);
                }
                 */

                //Edit ratings
                /*
                // Makes absolutely no sense to have this here...
                editMedia.Ratings.Clear();
                for (var i = media.Ratings.Count; i > 0; i--)
                {
                    var rating = media.Ratings.First();

                    var rat = context.RatingSet.FirstOrDefault(c => c.Id == rating.Id) ??
                              Rating.CreateRating(default(int), rating.Vote, rating.Created, rating.Updated, rating.UserId);

                    editMedia.Ratings.Add(rat);
                    media.Ratings.Remove(rating);
                }
                */

                //Edit comments
                /*
                // Makes absolutely no sense to have this here...
                editMedia.Comments.Clear();
                for (var i = media.Comments.Count; i > 0; i--)
                {
                    var comment = media.Comments.First();

                    var com = context.CommentSet.FirstOrDefault(c => c.Id == comment.Id) ??
                              Comment.CreateComment(default(int), comment.Text, comment.MediaId, comment.Created, comment.UserId, comment.Updated);

                    editMedia.Comments.Add(com);
                    media.Comments.Remove(comment);
                }
                */

                return context.SaveChanges() > 0;
            }
        }

        public bool DeleteMedia(int mId)
        {
            using (var context = new RentIt03Entities())
            {
                var media = context.MediaSet.FirstOrDefault(m => m.Id == mId);

                if (media != null)
                {
                    media.Languages.Clear();
                    media.Genres.Clear();

                    for (var i = media.Images.Count; i > 0; i--)
                        context.ImageSet.DeleteObject(media.Images.First());

                    for (var i = media.Ratings.Count; i > 0; i--)
                        context.RatingSet.DeleteObject(media.Ratings.First());

                    for (var i = media.Versions.Count; i > 0; i--)
                    {
                        var version = media.Versions.First();

                        for (var j = version.Purchases.Count; j > 0; j--)
                            context.PurchaseSet.DeleteObject(version.Purchases.First());

                        media.Versions.Remove(version);
                        context.VersionSet.DeleteObject(version);
                    }

                    context.MediaSet.DeleteObject(media);
                }

                context.MediaSet.DeleteObject(media);
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Media> OverviewMedia(MediaSearchParameter condition)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;

                var q = context.MediaSet.OfType<Media>();

                if (!String.IsNullOrWhiteSpace(condition.Title))
                    q = (ObjectQuery<Media>)q.Where(m => m.Title.Contains(condition.Title));

                if (condition.YearFrom > 0)
                    q =
                        (ObjectQuery<Media>)
                        q.Where(m => ((m.Year <= condition.YearTo) && (m.Year >= condition.YearFrom)));

                if (!string.IsNullOrWhiteSpace(condition.Genre))
                    q = (ObjectQuery<Media>)q.Where(m => m.Genres.ToString().Contains(condition.Genre));

                if (!string.IsNullOrWhiteSpace(condition.Description))
                    q = (ObjectQuery<Media>)q.Where(m => m.Description.Contains(condition.Description));

                var count = condition.Count != null && condition.Count > 0 ? condition.Count : 12;
                var page = condition.Page != null && condition.Page > 0 ? condition.Page : 0;

                return condition.Count < 0
                           ? new List<Media>(q.Count())
                           : q.OrderByDescending(m => m.Created).Skip((int)(page * count)).Take((int)count).ToList();
            }
        }

        public int OverviewMediaCount(MediaSearchParameter parem)
        {
            parem.Count = -1;
            return OverviewMedia(parem).Capacity;
        }

        [Pure]
        public bool MediaExists(Media media)
        {
            using (var context = new RentIt03Entities())
            {
                if (media.Title != null && media.Year > 0)
                {
                    return context.MediaSet.Any(m => m.Title == media.Title && m.Year == media.Year);
                }
                return false;
            }
        }

        //Genre methods

        public bool AddGenreToMedia(int gId, int mId)
        {
            using (var context = new RentIt03Entities())
            {
                var media = context.MediaSet.FirstOrDefault(m => m.Id == mId);
                var genre = context.GenreSet.FirstOrDefault(g => g.Id == gId);
                if (media != null)
                {
                    context.GenreSet.Attach(genre);
                    media.Genres.Add(genre);
                }
                return context.SaveChanges() > 0;
            }
        }

        public bool DeleteGenreFromMedia(int mId, int gId)
        {
            using (var context = new RentIt03Entities())
            {
                Media media = context.MediaSet.FirstOrDefault(m => m.Id == mId);
                if (media != null)
                    media.Genres.Remove((Genre)media.Genres.Where(g => g.Id == gId));
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Genre> OverviewMediaGenre(int mId)
        {
            using (var context = new RentIt03Entities())
            {
                var media = context.MediaSet.FirstOrDefault(m => m.Id == mId);
                return media != null ? media.Genres.ToList() : new List<Genre>();
            }
        }

        public int CreateGenre(Genre genre)
        {
            using (var context = new RentIt03Entities())
            {
                var gen = context.GenreSet.FirstOrDefault(g => g.Name == genre.Name && g.MediaType == genre.MediaType);

                if (gen == null)
                {
                    context.GenreSet.AddObject(genre);
                    context.SaveChanges();
                }
                else
                    genre = gen;

                return genre.Id;
            }
        }

        [Pure]
        public Genre ReadGenre(int gId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.GenreSet.FirstOrDefault(g => g.Id == gId);
            }
        }

        [Pure]
        public Genre ReadGenre(string name)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.GenreSet.FirstOrDefault(g => g.Name.Contains(name));
            }
        }

        public bool EditGenre(Genre genre, int gId)
        {
            using (var context = new RentIt03Entities())
            {
                var editGenre = context.GenreSet.FirstOrDefault(g => g.Id == gId);
                if (editGenre != null)
                {
                    editGenre.Name = genre.Name;
                    editGenre.MediaType = genre.MediaType;
                }
                return context.SaveChanges() > 0;
            }
        }

        public bool DeleteGenre(int gId)
        {
            using (var context = new RentIt03Entities())
            {
                var genre = context.GenreSet.FirstOrDefault(g => g.Id == gId);
                context.GenreSet.DeleteObject(genre);
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Genre> OverviewGenre()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.GenreSet.ToList();
            }
        }

        public List<Language> OverviewLanguage()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.LanguageSet.ToList();
            }
        }

        //Comment methods

        public int CreateComment(Comment comment)
        {
            using (var context = new RentIt03Entities())
            {
                comment.Id = default(int);
                comment.Updated = DateTime.Now;
                comment.Created = DateTime.Now;
                context.CommentSet.AddObject(comment);
                context.SaveChanges();
                return comment.Id;
            }
        }

        [Pure]
        public Comment ReadComment(int cId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.CommentSet.Include("User").FirstOrDefault(c => c.Id == cId);
            }
        }

        public bool EditComment(Comment comment, int cId)
        {
            using (var context = new RentIt03Entities())
            {
                var editComment = context.CommentSet.Include("User").FirstOrDefault(c => c.Id == cId);
                if (editComment != null)
                {
                    editComment.Text = comment.Text;
                    editComment.Updated = DateTime.Now;
                }
                return context.SaveChanges() > 0;
            }
        }

        public bool DeleteComment(int cId)
        {
            using (var context = new RentIt03Entities())
            {
                var comment = context.CommentSet.FirstOrDefault(c => c.Id == cId);
                context.CommentSet.DeleteObject(comment);
                return context.SaveChanges() > 0;
            }
        }

        [Pure]
        public List<Comment> GetComments(int mId)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.CommentSet.Include("User").Where(m => m.MediaId == mId).ToList();
            }
        }

        [Pure]
        public List<Media> Top10Purchases()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var query =
                    (from p in context.PurchaseSet group p by p.Id into pur orderby pur.Count() descending select pur)
                        .Take(10);
                var rentIt03Entities = context;
                return (from Purchase p in query where rentIt03Entities != null select (Media)rentIt03Entities.MediaSet.Where(m => m.Id == p.Id)).ToList();
            }
        }

        [Pure]
        public List<User> Top10Renters()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var query =
                    (from p in context.PurchaseSet
                     group p by p.UserId
                         into users
                         orderby users.Count() descending
                         select users).Take(10);
                var rentIt03Entities = context;
                return (from User user in query where rentIt03Entities != null select (User)rentIt03Entities.UserSet.Where(u => u.Id == user.Id)).ToList();
            }
        }

        [Pure]
        public List<Movie> TopRatedMovies(int page, int count)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.MediaSet.OfType<Movie>().OrderByDescending(m => m.Rating).Skip(page * count).Take(count > 0 ? count : 10).ToList();
            }
        }

        [Pure]
        public List<Movie> RandomMovies(int number)
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return context.MediaSet.OfType<Movie>().OrderBy(m => Guid.NewGuid()).Take(number > 0 ? number : 10).ToList();
            }
        }

        [Pure]
        public List<Ebook> Top10RatingEbook()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return (from m in context.MediaSet.OfType<Ebook>() orderby m.Rating descending select m).Take(10).ToList();
            }
        }

        [Pure]
        public List<Media> Top10Newest()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                return (from m in context.MediaSet orderby m.Released descending select m).Take(10).ToList();
            }
        }

        [Pure]
        public List<User> Top10Commenters()
        {
            using (var context = new RentIt03Entities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var query =
                    (from c in context.CommentSet
                     group c by c.UserId
                         into users
                         orderby users.Count() descending
                         select users).Take(10);
                var rentIt03Entities = context;
                return (from User user in query where rentIt03Entities != null select (User)rentIt03Entities.UserSet.Where(u => u.Id == user.Id)).ToList();
            }
        }
    }
}

public class RentitPermission
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class RentitRole
{
    public RentitRole()
    {
        Permissions = new List<string>();
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public List<string> Permissions { get; set; }
}